home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / pas2c.zip / PAS2C.DOC < prev    next >
Text File  |  1993-01-04  |  9KB  |  210 lines

  1. PAS2C.DOC
  2.  
  3.                     Linking Turbo Pascal and Turbo C
  4.  
  5.                   December 23, 1987        Martin Weigel
  6.  
  7. Synopsis:
  8.  
  9. Recently, I had need to link Turbo C and Turbo Pascal code together. This
  10. summarizes my efforts, and provides a useful utility routine. This document
  11. is *not* tutorial but is solely intended for technically astute users. I do
  12. entertain suggestions on the problem, and its solution(s), but *not* on the
  13. material or its presentation. *Only* source code is presented here, and
  14. you will have to have the required programs to make use of the material.
  15.  
  16. I encourage *free* distribution of this material. I strictly prohibit
  17. selling PASOBJ (give it away, *but* don't sell it).
  18.  
  19. Please let Borland know how you feel about their OBJ capability (or lack 
  20. thereof).
  21.  
  22. Requires:
  23.  
  24.     Borland Turbo C
  25.     Borland Turbo Pascal 4.0
  26.     Microsoft LIB
  27.  
  28. ---------------------------------------
  29.  
  30. PASOBJ:
  31.  
  32. Both Turbo C and Turbo Pascal 4 are fantastic compilers. Turbo C offers
  33. reasonable compilation speed, and *very* good code production. Turbo Pascal
  34. offers excellent type checking, screamingly fast compilation, and units.
  35.  
  36. In some projects, it would be nice to capitalize on the strengths of both
  37. of these Borland products. Unfortunately, there are some very basic
  38. compatibility problems which must be overcome before this dream can be
  39. successfully realized.
  40.  
  41. With the help of Kim Kokonnen, I have developed an interim solution, which
  42. should be effective for most applications. At least until Borland does
  43. something about the problems.
  44.  
  45. The first problem is one of segment naming. In order to import OBJ files,
  46. the OBJ files have to be structure with some *very* specific rules:
  47.  
  48.     - The code must be in a segment called CODE or CSEG
  49.     - The data must be in a segment called DATA or DSEG
  50.     - There must be no initialized data in the OBJ file
  51.     - All symbols *must* have legal Pascal identifiers
  52.     - There must be *no* groups or classes
  53.  
  54. Turbo C breaks *all* of these rules when it is producing code. First,
  55. the code segment name is _TEXT or xxx_TEXT, and the data is in two
  56. segments: _BSS for unitialized data and _DATA for initialized data.
  57. It "groups" _BSS and _DATA into a single segment. Initialized data is
  58. produced for every string constant and initialized variable (put into
  59. the _DATA segment). Turbo C assigns class names to all segments. Last,
  60. Turbo C *itself* generates identifiers which are not legal in Pascal
  61. (identifiers with an '@' symbol in the name).
  62.  
  63. All of these problems but the last one can be solved by instructing the
  64. Turbo C compiler to use different segment, group and class naming
  65. conventions, and by being rigid about the style of C code being used.
  66. The problem with the '@' sign in identifiers *cannot* be solved this
  67. way, because the C programmer is not in control over the use of these
  68. functions.
  69.  
  70. The Turbo C compiler will produce an '@' identifier every time it must
  71. use an "intrinsic" function. An intrinsic function can be viewed as
  72. an extension to the instruction set of the machine. Some of these
  73. intrinsic functions include Long Divide, Long Shift, and Structure
  74. Passing.
  75.  
  76. Another problem with changing the segment naming during the C compilation
  77. is that this technique only works if you have access to the C source code.
  78. I don't have a copy of the C Library Run-time source, and some of the
  79. routines I am interested in linking to are in that library.
  80.  
  81. The PASOBJ solves most of the problems. To compile PASOBJ, you will need
  82. the Turbo C compiler (if you don't have it, this is all pretty much
  83. useless to you anyway). Compile PASOBJ.C to PASOBJ.EXE using small model,
  84. no floating point (this is not critical, but results in the smallest EXE
  85. file).
  86.  
  87. PASOBJ takes one or two parameters. Both parameters are OBJ file names.
  88. If only one parameter is given, PASOBJ will process the OBJ file to
  89. itself (using a temporary file). If two names are given, the first file
  90. is taken as an input file, the second as the output file. WARNING: If
  91. the file fed to PASOBJ is *not* an OBJ file, strange things will happen!
  92. The .OBJ extension *must* be specified.
  93.  
  94. PASOBJ massages the OBJ file, changing segment names as appropriate for
  95. use with Turbo Pascal 4.0, and changing '@' characters in identifiers
  96. to benign '_' characters.
  97.  
  98.  
  99. Example:
  100.              lib cc *strlen      -- extract strlen.obj from cc.lib
  101.              pasobj strlen.obj   -- massage it for $L inclusion
  102.  
  103.  
  104. CINTRIN.PAS is the Pascal source code for a unit that will satisfy all
  105. of the C Intrinsic references. Edit, and the run batch file MAKECIN
  106. to produce the CINTRIN.TPU unit.
  107.  
  108. ---------------------------------------
  109.  
  110. SAVEREG:
  111.  
  112.  
  113. The Turbo C compiler produces its best code when it is allowed to use
  114. SI and DI as general registers. When Pascal is used to call a C function,
  115. this works, because C functions that use SI and DI save and restore the
  116. register values appropriately. If the C function calls a Pascal routine,
  117. the Pascal routine is at liberty to destroy the values contained in SI
  118. and DI. Turbo C provides an option (-r-) to support this, at the cost
  119. of worsening code generation. The two macros in SAVEREG.H also solve the
  120. problem, in a more efficient way. Every call from C to Pascal is to
  121. be wrapped in a save_registers/restore_registers pair:
  122.  
  123.         save_registers;
  124.         PASCAL_PROCEDURE();
  125.         restore_registers;
  126.  
  127. save_registers saves the contents of SI and DI before the call,
  128. restore_registers restores the contents of SI and DI after the call.
  129.  
  130. The PASCAL program must make a POINTER called __rsp available globally,
  131. and must point it to an area to be used as a save stack. 2 words are
  132. used on this stack every time save_registers is used. (see SAVEREG.PAS
  133. for an example that can be compiled into a unit).
  134.  
  135.         var
  136.             __rsp : Pointer;
  137.             SiDiStack : array [0..10] of Word;
  138.         ...
  139.         begin
  140.         __rsp := @SiDiStack[0];
  141.         ...
  142.         end.
  143.  
  144. save_registers and restore_registers are implemented as macros for
  145. efficiency.
  146.  
  147. ---------------------------------------
  148.  
  149. STD.H:
  150.  
  151. This is just my standards file, for machine portability. When compiling
  152. C programs for use by Pascal, I prefer COMPACT model. So STD.H enforces
  153. COMPACT model if the PASCAL define is given.
  154.  
  155. ---------------------------------------
  156.  
  157. An Example: TASK in C and Pascal
  158.  
  159. Files TASK.C, TASK.H and TASK.PAS implement a non-preemptive multi-tasker
  160. for Turbo Pascal V4.0, in C. See the source files for more documentation.
  161. Compile TASK.C in COMPACT model. Unit TASK.PAS requires CINTRIN.TPU and
  162. SETJMP.OBJ (from CC.LIB):
  163.  
  164.     lib \lib\cc *setjmp       -- pull C setjmp/longjmp functions from lib
  165.     pasobj setjmp.obj         -- massage them into TPAS 4 format
  166.     tpc task                  -- compile task unit
  167.  
  168. This tasker can run tasks written in either C or Pascal. It is not at
  169. all fancy, but serves 99.9% of all my needs. If you feel inclined,
  170. expand on it, but please send the results (including source) back to
  171. CompuServe.
  172.  
  173. ---------------------------------------
  174.  
  175. Outstanding Problems:
  176.  
  177. Every time a constant string is used in Turbo C, it places the string into
  178. initialized data (_DATA). Unfortunately, Turbo Pascal 4.0 cannot (will not?)
  179. import an OBJ file with initialized data (per the manual). This means that
  180. C library routines such as atoi cannot be used (becauses it, in turn uses
  181. __ctypes, which is an initialized array). Also, any user code like:
  182.  
  183.     send_string("showpage\n");
  184.  
  185. will not work.
  186.  
  187. A work-around for the string problem is to define the strings in the
  188. Turbo Pascal section, as in:
  189.  
  190.     const
  191.         _string1 : String[10] = 'showpage'#10#0;
  192.  
  193. and rework the C code to be:
  194.  
  195.     IMPORT TEXT *string1;      /* see STD.H for IMPORT and TEXT */
  196.     send_string(string1 + 1);
  197.  
  198. This is *not* nice, in fact, it's downright ugly. Any suggestions?
  199.  
  200. Another problem (much worse, in my opinion), is that *every* public
  201. identifier in the OBJ file being imported *must* be declared as a
  202. Pascal function or procedure identifier. This means that you will have
  203. to be very careful to make *every* function that is local to the C
  204. source a LOCAL (static) function. Kim Kokonnen has come up with another
  205. solution to this problem -- see PATCHTPC for a program to patch TPC.EXE
  206. to cure this nasty. (I've tried it and it seems to work ok).
  207.  
  208. ---------------------------------------
  209.  
  210.